package com.lnsystem.service.impl;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.lnsystem.common.StockCriteria;
import com.lnsystem.constants.LNSystemConstants;
import com.lnsystem.dao.AnalyticsEventDao;
import com.lnsystem.dao.StockDao;
import com.lnsystem.model.AnalyticsEvent;
import com.lnsystem.model.Stock;
import com.lnsystem.model.StockDailyData;
import com.lnsystem.service.AnalyticsService;
import com.lnsystem.service.BottommingAnalyticsService;
import com.lnsystem.service.ReportingService;
import com.lnsystem.service.StockCheckService;
import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils.Collections;

@Component
public class BottommingAnalyticsServiceImpl implements BottommingAnalyticsService {
	
	Logger logger = Logger.getLogger(BottommingAnalyticsServiceImpl.class);
	
	@Autowired
	StockDao stockDao;
	
	@Autowired 
	AnalyticsEventDao analyticsEventDao; 
	
	@Autowired 
	CandleAnalyticsServiceImpl candleAnalyticsServiceImpl;
	
	@Autowired
	StockCheckService stockCheckService;
	
	@Autowired
	private ReportingService reportingService;
	
	@Autowired 
	private AnalyticsService analyticsService;
	
	@Override
	public boolean isStockBottoming(Stock s, StockCriteria criteria) {
		
		// finds if there is a (recent?) candle with 
		// a. lower wick longer than upper wick
		// b. previous day was a down day (R)
		// and c. day's volume > 30day (configurable) volume 
	
		List<StockDailyData> dailyDataList = null;
		
		String priceAction;
		boolean isPrevDayNotWhite;
		boolean hasProperLowerWick;
		boolean hasHugeVolume;
		boolean hasLowerLow;
		boolean isInDownTrend = false;
		int averageVolDays = 0;
		
		if(criteria.getScanStartDate() == null) { // no specific scanning date range specified, so get all and start from today.
			dailyDataList = s.getStockDailyData();
			java.util.Collections.reverse(dailyDataList);
		} else {
			dailyDataList = stockDao.getStockDailyDataBeforeDate(s, criteria.getScanStartDate(), true);
		}
		if(dailyDataList!=null && dailyDataList.size()>1) { //checking if list has atleast 2 elements as we need to compare with prev day's data as well.
		
			if(criteria.getDaysForAveragingVolume()<=0) {
				averageVolDays = LNSystemConstants.DAYS_FOR_AVGVOL_CALCULATION;
			}
			BigInteger averageVolume = stockDao.getAverageVolume(s, averageVolDays);
			
			if(criteria.isTodayOnly()) {
				
				// return if it is not a reversal day if isReversalHammerOnly() is true..
				if(criteria.isReversalHammerOnly() && !(dailyDataList.get(0).getPriceAction().equalsIgnoreCase("H") 
						//|| dailyDataList.get(0).getPriceAction().equalsIgnoreCase("G")
						)){
					return false;
				}
				
				if(criteria.isDownTrendingOnly()){
					isInDownTrend = isShowingDownTrend(dailyDataList, LNSystemConstants.DAYS_FOR_DOWNTREND_CALCULATION);
				}

				if(!criteria.isDownTrendingOnly() || isInDownTrend) {
					priceAction = dailyDataList.get(1).getPriceAction();
					hasLowerLow  = dailyDataList.get(0).getLow() <= dailyDataList.get(1).getLow();
					isPrevDayNotWhite = priceAction.equals("R") || priceAction.equals("B");
					
					if(criteria.isBottomingWithHammerOnly()) {
						hasProperLowerWick = candleAnalyticsServiceImpl.isAHammer(dailyDataList.get(0));
					} else {
						hasProperLowerWick = candleAnalyticsServiceImpl.hasLowerWick(dailyDataList.get(0));
					}
					
					// if true, average or greater than average volume.
					hasHugeVolume = dailyDataList.get(0).getVolume().compareTo(averageVolume)>=0;
					
					if (isPrevDayNotWhite && hasLowerLow && hasProperLowerWick && hasHugeVolume){
						AnalyticsEvent event = analyticsEventDao.getAnalyticsEventsByTypeForADailyData(dailyDataList.get(0), "POTENTIAL_BOTTOM");
						if(event == null){
							analyticsService.addAnalyticsEvent(s, dailyDataList.get(0),"POTENTIAL_BOTTOM");
						} else {
							logger.info(">> There is already an event of type: POTENTIAL_BOTTOM for stock: "+s.getSymbol()+" on ["+dailyDataList.get(0).getDate()+"]");
						}
						return true;
					}

				}

			} else {

				//TODO add code to check for bottoming for this month or for a specific date range.
			}

			
		}
		return false;
	}

	@Override
	public List<Stock> getAllBottomingStocks(StockCriteria criteria){
		
		List<Stock> result = new ArrayList<Stock>();
		if(criteria!=null 
				&& criteria.getMinVolume()>0 
				&& criteria.getMinPrice()>0 
				&& criteria.getMaxPrice()>0) {
			
			List<Stock> stockList = stockDao.getStocksByPriceRangeOverCertainVolume(criteria.getMinPrice(), criteria.getMaxPrice(), criteria.getMinVolume());
			
			for(Stock stock : stockList) {
				if(isStockBottoming(stock, criteria)) {
					System.out.println(">>>>>>>>>>>>>> "+stock.getSymbol()+" potential bottom on "+criteria.getScanStartDate());
					result.add(stock);
				}
			}
		}
		
		//check stock's health
		stockCheckService.checkStock(result);
		
		//add the stocks showing pocket pivot to analyticsevent table..
		
		
		
		reportingService.generateReportOfStockPicks(
				"StocksPotentiallyBottoming",
				"Potential bottoming stocks on [" + criteria.getScanStartDate()
						+ "]"
						//+ ", basingOnly=" + basingStocksOnly
						+ ", pricerange/vol=[" + criteria.getMinPrice() + "-"
						+ criteria.getMaxPrice() + "," + criteria.getMinVolume() + "]", result);
		return result;
	}
	
	@Override
	public boolean isShowingDownTrend(List<StockDailyData> dailyDataList, int numberOfDays) {
		
		//for now check for the last 10 days
		// if 5 out of 10 (or 50%) of day have lower lows, then we can conclude it is downtrend.
		StockDailyData today;
		StockDailyData yesterday;
		double lowerLowsCount = 0;
		
		if(dailyDataList!=null && dailyDataList.size()>numberOfDays) {
			for(int i=0;i<numberOfDays;i++) {

				today = dailyDataList.get(i);
				yesterday = dailyDataList.get(i+1);
				
				if(today.getLow() <= yesterday.getLow()) {
					lowerLowsCount++;
				}
			}
			double lowerLowsPercentage = (lowerLowsCount/numberOfDays)*100; 
			//System.out.println("Total lowerLows = "+lowerLowsCount+", lowerLows% = "+lowerLowsPercentage);
			if(lowerLowsPercentage>=50) {
				return true;
			}
		}
		return false;
	}
}
